package com.xpec.net.xnetty.h5cihper;

import java.io.UnsupportedEncodingException;
import java.net.SocketAddress;
import java.util.HashMap;
import java.util.Random;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelFutureListener;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelStateEvent;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelHandler;

import com.xpec.c4.h5net.H5XSENetSession;
import com.xpec.c4.h5net.H5XSENetSessionPool;
import com.xpec.cipher.CipherConnectionConstant;
import com.xpec.cipher.handler.CipherConnectionPacketHandler;
import com.xpec.cipher.tals.TalsConstance;
import com.xpec.cipher.tals.Util;

/**
 * 安插於 訊息收送Pipeline 中的 Cipher Handler
 * XNetty 的實作版本
 */
public abstract class H5BaseCipherChannelHandler extends SimpleChannelHandler implements ChannelFutureListener
{
	
	private static final Log log = LogFactory.getLog(H5BaseCipherChannelHandler.class);
	
	/**
	 * 儲存各Cipher階段和對應的Cipher處理Handler。有效阻止switch-case
	 * 於子類中以 static 靜態方式加入成員即可
	 */
	protected static HashMap<Integer, CipherConnectionPacketHandler> handlers = new HashMap<Integer, CipherConnectionPacketHandler>();
	/**
	 * 取得某Cipher階段下負責處理的 Handler
	 */
	private CipherConnectionPacketHandler getHandler(int status){
		return handlers.get(status);
	}
	
	
	/**
	 * 儲存目前的Cipher階段
	 */
	protected void setConnectionStatus(int status){
		this.saveParameter(CipherConnectionConstant.PARA_KEY_STATUS, status);
	}
	/**
	 * 獲得目前的Cipher階段
	 */
	public int getConnectionStatus(){
		Object status = this.getParameter(CipherConnectionConstant.PARA_KEY_STATUS);
		return (Integer) status;
	}	
	
	
	protected static Random random = new Random(System.currentTimeMillis());
	/**
	 * 随机加密算法
	 */
	public static byte randomCipherAlgorithm(){
		byte cipherAlgo = (byte) (1);
		return cipherAlgo;
	}
	/**
	 * 随机Hmac算法
	 */
	public static byte randomHmacAlgorithm(){
		byte hmacAlgo = (byte) (random.nextInt(2) + 1);
		return hmacAlgo;
	}

	/**
	 * 用于接收消息的巨大的buffer，
	 * 所有的消息都先堆到这里，供handler慢慢消化处理。
	 * @auther Francois
	 */
	protected ChannelBuffer content;

	protected SocketAddress address;
	
	protected Object[] attributes = new Object[CipherConnectionConstant.MAX_SIZE];
	/**
	 * 将一些参数塞到Session中去
	 */
	public void saveParameter(Integer key, Object value){
		attributes[key] = value;
	}
	/**
	 * 获取session参数
	 */
	public Object getParameter(Integer key){
		return attributes[key];
	}
	
	
	/**
	 * 用來監聽 Cipher是否建立成功的 listener
	 * Cipher握手成功會呼叫 cipherConnected
	 */
	protected H5CipherFinishListener cipherConnectListener = null;
	public void notifyCipherFinish(Channel channel){
		if(cipherConnectListener!=null){
			H5XSENetSession session = H5XSENetSessionPool.getSession(channel );
			cipherConnectListener.cipherFinished(session);
		}
	}
	public H5CipherFinishListener getCipherConnectListener() {
		return cipherConnectListener;
	}
	public void setCipherConnectListener(H5CipherFinishListener cipherConnectListener) {
		this.cipherConnectListener = cipherConnectListener;
	}


	/**
	 * 重新改變 pipeline中的 channel
	 * @param channel 用 channel.getPipeline() 來取得 pipeline
	 */
	public abstract void addOtherHandler(Channel channel);

	private ChannelBuffer decodingBuffer = null;
	
	ChannelBuffer getBuff(ChannelHandlerContext ctx){
		return decodingBuffer;
	}
	
	void setBuff(ChannelBuffer buff){
		decodingBuffer = buff;
	}
	
	void removeBuff(ChannelHandlerContext ctx){
		decodingBuffer = null;
	}

	@Override
	public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception
	{
		ChannelBuffer content = getBuff(ctx);
		// 第一次收到buffer
		if (content == null)
		{
			ChannelBuffer buffer = (ChannelBuffer) e.getMessage();
			content = buffer.duplicate();
			setBuff(content);
		}
		else
		{
			ChannelBuffer recvContent = (ChannelBuffer) e.getMessage();
			
			//buffer空间不足
			if (content.writableBytes() < recvContent.readableBytes())
			{
				ChannelBuffer newContent = ChannelBuffers.buffer(content.readableBytes()
						+ recvContent.readableBytes());
				newContent.writeBytes(content);
				content = newContent;
				setBuff(content);
			}
			content.writeBytes(recvContent);
		}
	
		if (content != null)
		{
			try
			{
				receiveHandle(ctx, e, content);
			}
			catch (Exception ex) {
				log.error("receiveHandle error! disconnect! ",ex);
				ctx.getChannel().disconnect();
			}
		}
	}

	@Override
	public void writeRequested(ChannelHandlerContext ctx, MessageEvent e) throws Exception
	{
		sendHandle(ctx, e);
	}


	private void sendHandle(ChannelHandlerContext ctx, MessageEvent e)
	{
		int status = getConnectionStatus();
		CipherConnectionPacketHandler handler = getHandler(status);
		if(handler != null){
			handler.sendHandle( new H5XNettyCipherHandler(ctx, e, this) );
		}
	}

	/**
	 * GET / HTTP/1.1\r\n 
	 * Host: app27197.qzoneapp.com:80\r\n\r\n</br>
	 * 新版的：tgw_l7_forward\r\nHost: app27197.qzoneapp.com:8002\r\n\r\n
	 * client连接的第一个消息会发HTTP头，参照TGW文档。 
	 */
	private static final int HTTPHEAD_LENGTH = 52;
	private static byte[] rnBytes;
	private static int HTTPHEAD_START_BYTES;
	static {
		try {
			//新版的tgw协议
			byte[] bytes = "tgw_l7_forward\r\nHost: app27197.qzoneapp.com:8002\r\n\r\n".getBytes("GBK");
			byte[] intBytes = new byte[4];
			intBytes[0] = bytes[0];
			intBytes[1] = bytes[1];
			intBytes[2] = bytes[2];
			intBytes[3] = bytes[3];
			HTTPHEAD_START_BYTES = Util.transByteArrayToInteger(intBytes);
			rnBytes = "\r\n".getBytes("GBK");
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		
	}
	
	public static void main(String args[]) 
	{
		try {
			byte[] bytes1 = "GET / HTTP/1.1\r\nHost: app27197.qzoneapp.com:80\r\n\r\n".getBytes("GBK");
			byte[] bytes2 = "GET / HTTP/1.1\r\nAccept: */*\r\nHost: app27197.qzoneapp.com\r\n\r\n".getBytes("GBK");
			byte[] b = "\r\n".getBytes("GBK");
			output4Bytes(bytes1);
			output4Bytes(bytes2);
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
	}


	private static void output4Bytes(byte[] bytes1)
	{
		byte[] intBytes = new byte[4];
		intBytes[0] = bytes1[0];
		intBytes[1] = bytes1[1];
		intBytes[2] = bytes1[2];
		intBytes[3] = bytes1[3];
		System.out.println(Util.transByteArrayToInteger(intBytes));
	}
	
	private void receiveHandle(ChannelHandlerContext ctx, MessageEvent e, ChannelBuffer realContent)
	{
		while (realContent.readableBytes() > TalsConstance.UINT32_SIZE)
		{
			// 只取一个length record的内容
			ChannelBuffer slice = realContent.slice();

			// realContent需要去掉长度的信息
			byte[] lengthBytes = new byte[TalsConstance.UINT32_SIZE];
			// 消除了buffer的length部分
			slice.readBytes(lengthBytes, 0, TalsConstance.UINT32_SIZE);

			// 如果是HTTP头，需要去掉，支持TGW
			int length = Util.transByteArrayToInteger(lengthBytes);
			if (length > TalsConstance.MAX_DATA_PACKAGE_SIZE)
			{
				throw new IllegalStateException("Tals package length is bigger than "
						+ TalsConstance.MAX_DATA_PACKAGE_SIZE + "!");
			}

			// length是包括了刚才读的长度int的
			// 如果长度过小了，是一个socket没有传完，break出去等下次
			int contentLength = length - TalsConstance.UINT32_SIZE;
			if (slice.readableBytes() < contentLength)
			{
				break;
			}

			ChannelBuffer temp = ChannelBuffers.buffer(length);
			slice.readBytes(temp, contentLength);
			realContent.skipBytes(slice.readerIndex());

			int status = getConnectionStatus();
			CipherConnectionPacketHandler handler = getHandler(status);
			if(handler != null){
				handler.receiveHandle(new H5XNettyCipherHandler(ctx, e, temp, this));
			}
		}
	}

	@Override
	public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent event)
		throws Exception
	{
		removeBuff(ctx);
		super.channelDisconnected(ctx, event);
	}
}
